home *** CD-ROM | disk | FTP | other *** search
/ Gold Medal Software 1 / Gold Medal Software Volume 1 (Gold Medal) (1994).iso / prog / cextract.arj / CEXTRACT.TAR / cextract / parse.c < prev    next >
Encoding:
Text File  |  1993-08-08  |  53.1 KB  |  2,028 lines

  1. /*
  2.  *
  3.  * main parsing routines for the cextract/cextdoc programs.
  4.  * Also includes a number of generic routines applicable to both.
  5.  *
  6.  * These routines provide the methods used to extract comments,
  7.  * prototypes and function names from C source files.
  8.  *
  9.  * Copyright (c) 1990, 1991, 1992 by Adam Bryant
  10.  *
  11.  * The only restrictions on the use of these routines is that they not
  12.  * be used for monetary gain, and that this copyright notice be left
  13.  * intact.
  14.  *
  15.  * Note:  These programs may be freely used to extract code and/or
  16.  *        documentation at proprietary/corporate sites, as long as the
  17.  *        actual source code is not used within any proprietary code.
  18.  *
  19.  *        The generated output (header) files are distributable in any
  20.  *        manner desired as they are based on the scanned source code,
  21.  *        not my program.
  22.  */
  23. /*
  24.  * Version history:
  25.  *
  26.  * Changes for Version 0.40 of both cextract and cextdoc:
  27.  *    - implemented new out_char() interface.
  28.  *    - first comments will not be shown if no functions exist.
  29.  *    - implemented concatenation of comments.
  30.  *    - implemented troff output for cextdoc portion.
  31.  *
  32.  * Changes for Version 0.41 of both cextract and cextdoc:
  33.  *    - switched the NO_SETBUFFER to SETBUFFER, making non-use standard.
  34.  *    - added in the DO_VARARGS code to automatically account for the
  35.  *      the variable argument setup in parsing.
  36.  *
  37.  * Changes for Version 0.42 of both:
  38.  *    - made the DO_VARARGS code the default.  (removed #ifdefs)
  39.  *
  40.  * Changes for Version 0.50 (1/18/91) of both:
  41.  *    - added the configuration file code.
  42.  *    - removed much of the DEBUG print statements from stable code.
  43.  *    - made the bad syntax encounters exit the program.
  44.  *
  45.  * Changes for Version 0.51 (1/21/91) of both:
  46.  *    - implemented code to allow compilation on VAX VMS systems.
  47.  *
  48.  * Changes for Version 0.60 (4/15/91) of both:
  49.  *    - more VMS stuff, and addition of files: patchlevel.h,
  50.  *      README, and INSTALL.
  51.  *    - removed all other DEBUG statements.
  52.  *    - left the SETBUFFER code in place, but removed mention
  53.  *      of it from the Makefile, since there was no noticable
  54.  *      speed enhancement through its use.
  55.  *    - upgraded to version 6.0 for release to comp.sources.reviewed.
  56.  *
  57.  * Changes for Version 1.0 (4/17/91-5/3/91) of both:
  58.  *    - removed most system definitions from cproto.h and replaced
  59.  *      with more includes of system header files.  But, there are
  60.  *      still a number of system functions which are not in the header
  61.  *      files on at least Sun systems.
  62.  *    - now use the "is_switch()" function to parse the command line
  63.  *      arguments.  This allowed me to use both '-' and '/' on VMS
  64.  *      systems to avoid confusion in the manual pages.
  65.  *    - simplified the Makefile, especially for the "make install".
  66.  *    - fixed various mispellings/misphrasings in error messages.
  67.  *    - checked the argument in calls to free() within pop_proto().
  68.  *    - configuration files will be checked for in the following order:
  69.  *        system file, home directory, current directory.
  70.  *      any encountered will be read in.  This will allow overriding
  71.  *      of customization options in a logical order.
  72.  *    - implemented switch to control how the config files are read in.
  73.  *    - redid the manual pages and split out the customization section
  74.  *      into its own manual page.
  75.  *    - adjusted the comment capturing code to assure that it doesn't
  76.  *      misassign comments to the wrong functions.
  77.  *    - fixed one minor memory leak.
  78.  *    - adjust system configuration file locations.
  79.  *    - redid VMS popen() and pclose() to assure unique temporary file.
  80.  *    - added in an "err_msg()" routine to call perror() if it exits.
  81.  *    - made sure to check return value of all calls to fputs().
  82.  *    - merged "cextdoc" into "cextract".
  83.  *    - added verbose command line options with same format as the
  84.  *      configuration commands.
  85.  *    - now use the "+" and "-" switches to indicate on and off.
  86.  *    - added a number of new options to support the new merged
  87.  *      programs and to allow displaying of settings.
  88.  *    - added a -Hstring to indicate replacement of the sequence:
  89.  *
  90.  *          #ifndef __CEXTRACT__
  91.  *            ... output ...
  92.  *          #endif
  93.  *
  94.  *      with:
  95.  *
  96.  *          #ifndef string
  97.  *          #define string
  98.  *            ... output ...
  99.  *          #endif
  100.  *
  101.  *    - wrote up a VMS help file for cextract.
  102.  *
  103.  * Version 1.1: Okay, so there were still more changes needed. :-)
  104.  *    - fixed more occurances of proceed instead of precede.
  105.  *    - fixed typos of "it's" instead of "its".
  106.  *    - removed empty targets from Makefile
  107.  *    - add sed facility to Makefile to properly configure man pages.
  108.  *    - wrote a ".so" implementation for cextdoc manual instead of
  109.  *      prior hard link method.
  110.  *    - added a MANDIR variable to the Makefile.
  111.  *    - tweaked the documentation in a few places.
  112.  *    - allow the "!" or "no-" (Non-VMS) or "no" (VMS) prefix to
  113.  *      command line options.
  114.  *    - use "sys$login:" as HOME directory on VMS systems, if HOME
  115.  *      environment variable is not defined.
  116.  *    - changed the "sys$system:" to "sys$library".
  117.  *    - fixed typo of "fclose(*stream)" in the VMS pclose.
  118.  *    - adjusted the VMS qualifier building to build /define=(a,b,c), etc.
  119.  *    - added in a "remove-names" option to eliminate variable names
  120.  *      from the parameter list output.
  121.  *    - fixed strncmp() bug in the check for the "replace" option.
  122.  *    - fixed a number of calls to cfg_err() to pass cmd_line parameter.
  123.  *    - implemented better check for empty or "void" parameter lists.
  124.  *    - merged the void check and style determination into one routine
  125.  *      and called it diverge_style().
  126.  *    - changed a number of routines to use char* math instead of
  127.  *      array stepping using counters.
  128.  *    - added a configuration file section to the VMS help file.
  129.  *    - tweaked the cextract.1 and cextrc.5 manual pages a bit more.
  130.  *    - edited the README, INSTALL, and INSTALL.VMS files.
  131.  *    - implemented checks to be sure that the files to be parsed are
  132.  *      accessible before calling the C preprocessor.
  133.  *    - renamed the files as:
  134.  *         cproto.c     =>   parse.c
  135.  *         cproto.h     =>   xtract.h
  136.  *         cextract.c   =>   main.c
  137.  *      this was done to avoid some of the conflict with files
  138.  *      beginning with the same string of characters.
  139.  *    - made sure that "make test" tested the version in the current
  140.  *      directory.
  141.  *
  142.  * Version 1.2:  yet another pre-submission fix section.
  143.  *    - fixed a typo in the comments.
  144.  *    - separated the INSTALL definition in the Makefile into INSTBIN
  145.  *      and INSTMAN command to allow those systems without "install"
  146.  *      to perform installations properly.
  147.  *    - added "/exe=cextract" to the build.com link operation.
  148.  *    - fixed the character count in the copy_str() function.
  149.  *      [This fixes the misread on the "replace" operation].
  150.  *    - fixed up the "method" description in the README.
  151.  *    - added ${CEXTRACT} to the "test" (ala "make test") dependency.
  152.  *    - removed the "make links" and appended it to "make install"
  153.  *    - changed the "skip-config" command to "read-config".
  154.  *    - had one more go at the cextrc.5 manual page.
  155.  *    - tweaked the cextract.1 manual page as well.
  156.  *    - added check for declaration of array of function pointers.
  157.  *    - added code to parse structure declarations within function
  158.  *      parameter lists.  [why anyone would program like this is
  159.  *      beyond me, but hey, I like to support valid C.]
  160.  *    - made sure to only test for functions where a brace was
  161.  *      preceded by a semi-colon or a paranthesis.
  162.  *    - make sure to clear out the "code_info" array more often.
  163.  *    - increased the array sizes to allow for larger buffer space.
  164.  *      [temporary until implement dynamic memory routines.]
  165.  *    - created a TODO file and removed those items from the bottom
  166.  *      of the README file.
  167.  *    - shortened the BUGS section of the cextract.1 manual page.
  168.  *    - changed the program name check to strncmp() so VMS sites work.
  169.  *    - created a newbuild.com file and mentioned it in INSTALL.VMS.
  170.  *    - fixed errors in the newbuild.com file.
  171.  *    - added a mentioning of the '/' character for VMS options.
  172.  *    - cleaned up the README, INSTALL and other docs.
  173.  *
  174.  * Version 1.3:  first patch after comp.sources.reviewed
  175.  *    - fixed bug where comments within parameter list could cause a
  176.  *    function to be skipped.
  177.  *    - added both the CPP and CPP_COMMENTS flags to the Makefile.
  178.  *    - added patch from Martin Fouts (fouts@bozeman.clipper.ingr.com)
  179.  *    to provide simple changes to allow port to the CLIX OS.
  180.  *    - fixed stupid bug which caused the "-U" flag to not get parsed.
  181.  *    - changed the "#ifdef __STDC__" to the proper "#if __STDC__".
  182.  *    - wrote a new command and flag "build-config" to generate the system
  183.  *    configuration file automatically.  [-B or -b for build]
  184.  *    - made sure the replace macros do not contain duplicates.
  185.  *    - prevented the creation of duplicate '-D','-I', or '-U' entries.
  186.  *    - fixed the "macro_match()" function for all systems. [VMS?]
  187.  *    - reversed the definitions of CFLAGS and COPTS in the Makefile.
  188.  *    - made sure to test if substitution already took place in vargs_find().
  189.  *    - fixed the 'Q' flag so that it properly reads in any numeric.
  190.  *    - added a dependency for the system configuration file to the
  191.  *      "install" target, so that it can be automatically generated.
  192.  *    - fixed the INSTALL, INSTALL.VMS and documentation files to
  193.  *      properly cover the new configuration file building mechanism.
  194.  *    - implemented a better method for the NO_OPEN option.  This should
  195.  *      now work for all systems, not just VMS.
  196.  *    - fixed bug that the type of the function was not checked for
  197.  *      replacement.
  198.  *    - made sure that the subst macros where ordered as they came in.
  199.  *    - fixed bug with parameters for function pointers getting int
  200.  *      tagged on unnecessarily.
  201.  *
  202.  * Version 1.4:  [2/25/92-4/20/92]  Another iteration of fixes.
  203.  *    - allow any sort of text inside of brackets and parenthesis
  204.  *      in the variable declarations.
  205.  *    - fixed the fprintf formats in the font error messages.
  206.  *    - made sure to remove the use of register in prototype types.
  207.  *    - added the +Z option to allow for the compression of the output
  208.  *      using a macro.  [Also under the "merge-output" option.]
  209.  *    - separated functions into a third file [io.c] to reduce the
  210.  *      size of the other files.
  211.  *
  212.  * Version 1.5: [4/29/92-5/18/92] Second submission fixes.
  213.  *    - added ability to exclude all but static functions from search
  214.  *    to allow for the creation of header files for single files.
  215.  *    - fixed the documentation to reflex the new "static" feature.
  216.  *    - fixed some errors in the manual pages.
  217.  *    - adjusted the Makefile:  make echo, sed, nroff and install
  218.  *    configurable; had the "make test" command perform the diff
  219.  *    directly; enhanced the mkdir lines (is it portable?).
  220.  *    - fixed a bug in the out_str() function where it might have
  221.  *    accessed invalid data if the parameter str was NULL.
  222.  *    - for the SGI systems, added a "#define _POSIX_SOURCE" line.
  223.  *    - allow both "no-" and "no" for turning off options.
  224.  *    - implemented a "+W" ("+break-after-types") flag to separate
  225.  *    function type from the function name.
  226.  *    - implemented a "+w#" ("+wrap-parameters") flag to cause the
  227.  *    output of the parameter list to wrap after a given number of
  228.  *    characters.
  229.  *    - added the two new options to the documentation files.
  230.  *    - made use of minmatch_str's return value in io.c and cleaned up
  231.  *    some minor typos.
  232.  *    - fixed serious bug with the default settings for statics.
  233.  *    [Thanks to Jon Whellams for catching this.  *sigh*]
  234.  *    - major rewrite of the options system:
  235.  *      +  merged most of the options into a two dimensional array.
  236.  *      +  used this two-dimensional array to distinguish between
  237.  *         options used in extract mode and doc mode.
  238.  *      +  this makes it possible for the generated config files to
  239.  *         contain the proper "extract-only " or "doc-only "
  240.  *         prefixes.
  241.  *    - merged the two static flags into one flag with multiple
  242.  *    options, removing the confusing "-only-statics" flag.
  243.  *    - fixed the build_rc() routine to properly prefix "doc-only " or
  244.  *    "extract-only " to the output when appropriate.
  245.  *    - the mode ("extract", "doc", etc.) will no longer be written
  246.  *    when a configuration file is generated so "cextdoc" works.
  247.  *
  248.  * Version 1.6: [8/28/92] Third submission fixes.
  249.  *    - added line to set the permissions on the config file during install.
  250.  *    - regenerated the proto.h file to grab the main.c "parce.c" typo fix.
  251.  *    - fixed the documentation for the "-w#" flag. ["-w=#" --> "-w#"]
  252.  *    - for the INSTALL file, I now explicitly mention that installation
  253.  *    of the configuration file might need root permission.
  254.  *    - fixed outdated usages of pclose [pclose -> close_input].
  255.  *    - fixed the wrong usage of "command" in the "open_input" function.
  256.  *    - allow for alternative return values from system().
  257.  *    - make sure that multiple replacements can take place.
  258.  *    - fixed error with "replace" not recognizing "name" selection.
  259.  *    - made sure an error is printed if a bad "replace" format is seen.
  260.  *    - added support for // comments to begin future C++ support.
  261.  *    - provided a "strstr()" function for Xenix sites.
  262.  *    - expanded the "output-file" argument to support separate output
  263.  *    files for extraction and documentation modes.
  264.  *    - added the ability to select the C preprocessor at runtime.
  265.  *    - updated all of the documentation to reflect the above changes.
  266.  *    - preserve the doc/extract selection for macros and replace commands.
  267.  *
  268.  * Version 1.7: [10/30/92] Hopefully last enhancements before acceptance
  269.  *    - keep track of line numbers within the file being parsed.
  270.  *    - any syntax errors will be reported without aborting the file
  271.  *    parsing.
  272.  *    - syntax errors will be accurately reported by file and line number.
  273.  *    - added a check to test for too many left parenthesis.
  274.  *
  275.  */
  276. #include "xtract.h"
  277.  
  278. /* storage elements */
  279. P_PROTO proto_list = NULL, proto_next = NULL;
  280. P_MACRO macro_list = NULL, last_macro = NULL;
  281. P_SUBST subst_list = NULL, last_subst = NULL;
  282. FILE *fpin = NULL;
  283. char code_info[MAX_SIZE+1], cfg_file[MID_SIZE];
  284. char dummy_str[MID_SIZE], file_name[MID_SIZE];
  285. int arg_ch_count = 0;
  286. int out_file_flag = 0, comment_len = 0, dont_space = TRUE;
  287. char start_comment[MAX_SIZE];
  288. char prog_name[FNAME_SIZE];
  289. char tmp_str[FNAME_SIZE];
  290. int dont_stop = FALSE;
  291. static char last_comment[MAX_SIZE];
  292.  
  293. /* options for the different parsing methods */
  294. int global_opts[2][OPT_NUMBER];
  295. int doc_extract = DOC_NONE, cfg_switch = 7;
  296.  
  297. /* variables for keeping track of things */
  298. char errout_filename[MID_SIZE];
  299. int start_block = FALSE, files_parsed = 0, total_out = 0;
  300. int line_count = 0;
  301.  
  302. /* default font values */
  303. char ft_title[3] = "C";
  304. char ft_comment[3] = "CO";
  305. char ft_name[3] = "B";
  306. char ft_plist[3] = "R";
  307.  
  308. /* add a new substitution macro to the substitution list */
  309. void
  310. add_subst(type, select, f_str, t_str)
  311.   int type, select;
  312.   char *f_str, *t_str;
  313. {
  314.   P_SUBST subst_tmp;
  315.  
  316.   /* check for duplicates */
  317.   for (subst_tmp = subst_list;
  318.        subst_tmp != NULL;
  319.        subst_tmp = subst_tmp->next) {
  320.     if ((subst_tmp->submode == type) &&
  321.     (subst_tmp->usewhen == select) &&
  322.     (strcmp(subst_tmp->from_str, f_str) == 0)) {
  323.  
  324.       /* can exit routine for complete matches */
  325.       if (strcmp(subst_tmp->to_str, t_str) == 0) {
  326.     return;
  327.       }
  328.  
  329.       /* otherwise just adjust the replacement */
  330.       free(subst_tmp->to_str);
  331.       if ((subst_tmp->to_str =
  332.        (char *) malloc(sizeof(char) * (1 + strlen(t_str)))) == NULL) {
  333.     fprintf(stderr, "Serious Error: Memory Allocation Failure\n");
  334.     exit(1);
  335.       }
  336.       strcpy(subst_tmp->to_str, t_str);      
  337.       return;
  338.  
  339.     }
  340.   }
  341.  
  342.   /* allocate the memory space */
  343.   if ((subst_tmp = (P_SUBST) malloc(sizeof(S_SUBST))) == NULL) {
  344.     fprintf(stderr, "Serious Error: Memory Allocation Failure\n");
  345.     exit(1);
  346.   }
  347.   if (subst_list == NULL) {
  348.     subst_list = subst_tmp;
  349.   }
  350.   if ((subst_tmp->from_str =
  351.        (char *) malloc(sizeof(char) * (1 + strlen(f_str)))) == NULL) {
  352.     fprintf(stderr, "Serious Error: Memory Allocation Failure\n");
  353.     exit(1);
  354.   }
  355.   if ((subst_tmp->to_str =
  356.        (char *) malloc(sizeof(char) * (1 + strlen(t_str)))) == NULL) {
  357.     fprintf(stderr, "Serious Error: Memory Allocation Failure\n");
  358.     exit(1);
  359.   }
  360.  
  361.   /* now record the information */
  362.   subst_tmp->submode = type;
  363.   subst_tmp->usewhen = select;
  364.   strcpy(subst_tmp->from_str, f_str);
  365.   strcpy(subst_tmp->to_str, t_str);
  366.  
  367.   /* place the new link at the end of the chain */
  368.   subst_tmp->next = NULL;
  369.   if (last_subst != NULL) {
  370.     last_subst->next = subst_tmp;
  371.   }
  372.   last_subst = subst_tmp;
  373. }
  374.  
  375. /* add a new macro to the macro list */
  376. void
  377. add_macro(select, str)
  378.   int select;
  379.   char *str;
  380. {
  381.   P_MACRO macro_tmp;
  382.  
  383.   /* check for duplicate entries */
  384.   for (macro_tmp = macro_list;
  385.        macro_tmp != NULL;
  386.        macro_tmp = macro_tmp->next) {
  387.     /* no need to add something already there */
  388.     if (strcmp(macro_tmp->m_str, str) == 0) {
  389.       /* check for selection change */
  390.       if (macro_tmp->usewhen != select) {
  391.     macro_tmp->usewhen = 2;
  392.       }
  393.       return;
  394.     }
  395.   }
  396.  
  397.   /* allocate the space */
  398.   if ((macro_tmp = (P_MACRO) malloc(sizeof(S_MACRO))) == NULL) {
  399.     fprintf(stderr, "Serious Error: Memory Allocation Failure\n");
  400.     exit(1);
  401.   }
  402.   if (macro_list == NULL) {
  403.     macro_list = macro_tmp;
  404.   }
  405.   if ((macro_tmp->m_str =
  406.        (char *) malloc(sizeof(char) * (strlen(str) + 1))) == NULL) {
  407.     fprintf(stderr, "Serious Error: Memory Allocation Failure\n");
  408.     exit(1);
  409.   }
  410.   strcpy(macro_tmp->m_str, str);
  411.   macro_tmp->usewhen = select;
  412.   macro_tmp->next = NULL;
  413.   if (last_macro != NULL) {
  414.     last_macro->next = macro_tmp;
  415.   }
  416.   last_macro = macro_tmp;
  417. }
  418.  
  419. /* return TRUE if the macro definition is in the string */
  420. static int
  421. macro_match(macro, str)
  422.   char *macro, *str;
  423. {
  424.   static int deflen = -1;
  425.   int i, len, hold = FALSE;
  426.  
  427.   /* initialize */
  428.   if (deflen == -1) {
  429.     deflen = strlen(DEF_LEADER);
  430.   }
  431.  
  432.   /* check it */
  433.   if (strncmp(macro, DEF_LEADER, deflen) == 0) {
  434.     len = strlen(str);
  435.     for (i = 0; i < len; i++) {
  436.       if (macro[i + deflen] != str[i]) break;
  437.     }
  438.     if ((i == len) &&
  439.     ((macro[i + deflen] == '=') ||
  440.      (macro[i + deflen] == '\0'))) {
  441.       hold = TRUE;
  442.     }
  443.   }
  444.  
  445.   return(hold);
  446. }
  447.  
  448. /* if the matching definition is in the list, remove it */
  449. int
  450. removed_macro(select, str)
  451.   int select;
  452.   char *str;
  453. {
  454.   P_MACRO macro_ptr, macro_tmp;
  455.   int hold = FALSE;
  456.  
  457.   /* go through the list */
  458.   if ((macro_ptr = macro_list) != NULL) {
  459.  
  460.     /* check the beginning element */
  461.     if (macro_match(macro_ptr->m_str, str)) {
  462.       if (macro_ptr->usewhen != select) {
  463.     /* just return */
  464.     return(FALSE);
  465.       } else {
  466.     macro_list = macro_list->next;
  467.     macro_ptr->next = NULL;
  468.     free(macro_ptr->m_str);
  469.     free(macro_ptr);
  470.     hold = TRUE;
  471.       }
  472.     }
  473.  
  474.     /* check the rest */
  475.     macro_tmp = macro_ptr->next;
  476.     while (hold == FALSE && macro_tmp != NULL) {
  477.       if (macro_match(macro_tmp->m_str, str)) {
  478.     if (macro_ptr->usewhen != select) {
  479.       /* just return */
  480.       return(FALSE);
  481.     } else {
  482.       macro_ptr->next = macro_tmp->next;
  483.       macro_tmp->next = NULL;
  484.       free(macro_tmp->m_str);
  485.       free(macro_tmp);
  486.       hold = TRUE;
  487.     }
  488.       }
  489.  
  490.       /* onto the next */
  491.       macro_ptr = macro_tmp;
  492.       macro_tmp = macro_tmp->next;
  493.     }
  494.   }
  495.  
  496.   /* now assign the last_macro value and get back to work */
  497.   if (hold == TRUE) {
  498.     for (last_macro = macro_list;
  499.      (last_macro != NULL) &&
  500.      (last_macro->next != NULL);
  501.      last_macro = last_macro->next) ;
  502.   }
  503.   return(hold);
  504. }
  505.  
  506. /* compare two strings considering cases the same */
  507. int
  508. str_test (s1, s2)
  509.   char *s1, *s2;
  510. {
  511.   int ch1, ch2;
  512.  
  513.   for (; *s1 != '\0'; s1++, s2++) {
  514.     ch1 = (islower(*s1) ? toupper(*s1) : *s1);
  515.     ch2 = (islower(*s2) ? toupper(*s2) : *s2);
  516.     if (ch1 != ch2) return(ch1 - ch2);
  517.   }
  518.   return(*s1 - *s2);
  519. }
  520.  
  521. /* sort the list of functions and their prototypes */
  522. void
  523. sort_proto()
  524. {
  525.   P_PROTO p2_ptr;
  526.   int done = FALSE;
  527.  
  528.   /* all done? */
  529.   if ((proto_list == NULL) || (proto_list->next == NULL)) return;
  530.  
  531.   /* go until done sorting */
  532.   while (done == FALSE) {
  533.  
  534.     /* initialize */
  535.     proto_next = proto_list;
  536.     done = TRUE;
  537.  
  538.     /* test for initial swap */
  539.     if ( str_test( proto_next->name, (proto_next->next)->name ) > 0) {
  540.       proto_list = proto_next->next;
  541.       proto_next->next = proto_list->next;
  542.       proto_list->next = proto_next;
  543.       proto_next = proto_list;
  544.     }
  545.     
  546.     /* sort remaining linked list */
  547.     for (; (proto_next->next)->next != NULL; proto_next = proto_next->next) {
  548.       p2_ptr = (proto_next->next)->next;
  549.       if ( str_test( (proto_next->next)->name, p2_ptr->name ) > 0) {
  550.  
  551.     /* swap locations in list */
  552.     (proto_next->next)->next = p2_ptr->next;
  553.     p2_ptr->next = proto_next->next;
  554.     proto_next->next = p2_ptr;
  555.  
  556.     /* continue sort */
  557.     done = FALSE;
  558.       }
  559.     }
  560.  
  561.   }
  562. }
  563.  
  564. /* remove the top item on the stack */
  565. void
  566. pop_proto()
  567. {
  568.   P_PROTO tmp_proto = proto_list;
  569.  
  570.   /* done? */
  571.   if (proto_list == NULL) {
  572.     proto_next = NULL;
  573.     return;
  574.   }
  575.   if (proto_list == proto_next) {
  576.     proto_next = NULL;
  577.   }
  578.  
  579.   /* now do it */
  580.   proto_list = proto_list->next;
  581.   tmp_proto->next = NULL;
  582.   if (tmp_proto->name != NULL) free(tmp_proto->name);
  583.   if (tmp_proto->ftype != NULL) free(tmp_proto->ftype);
  584.   if (tmp_proto->fname != NULL) free(tmp_proto->fname);
  585.   if (tmp_proto->plist != NULL) free(tmp_proto->plist);
  586.   if (tmp_proto->comment != NULL) free(tmp_proto->comment);
  587.   free(tmp_proto);
  588. }
  589.  
  590. /* initialize the page for troff output, if needed */
  591. void
  592. init_roff(omode)
  593.   int omode;
  594. {
  595.   static int init_done = FALSE;
  596.  
  597.   /* perform the initialization */
  598.   if (init_done == FALSE) {
  599.     out_str(omode, ".sp 0.5i\n");
  600.     out_str(omode, ".ps 10\n");
  601.     out_str(omode, ".vs 12\n");
  602.     out_str(omode, ".fp 1 ");
  603.     out_str(omode, ft_title);
  604.     out_str(omode, "\n.fp 2 ");
  605.     out_str(omode, ft_comment);
  606.     out_str(omode, "\n.fp 3 ");
  607.     out_str(omode, ft_name);
  608.     out_str(omode, "\n.fp 4 ");
  609.     out_str(omode, ft_plist);
  610.     out_char(omode, '\n');
  611.     init_done = TRUE;
  612.   }
  613. }
  614.  
  615. /* check preprocessor statement for line numbering changes */
  616. int
  617. preprocessor_check()
  618. {
  619.   int curr_char = '#';
  620.   int i, l, line_value;
  621.   char temp_str[MID_SIZE], t2_str[MID_SIZE];
  622.  
  623.   /* get the whole line */
  624.   if (fgets(temp_str, MID_SIZE, fpin) != NULL) {
  625.     /* first handle the exit */
  626.     l = strlen(temp_str);
  627.     curr_char = temp_str[l - 1];
  628.  
  629.     /* now parse things */
  630.     for (i = 0; i < l; i++) {
  631.       if (isdigit(temp_str[i])) {
  632.     if (sscanf(&(temp_str[i]), "%d %s", &line_value,
  633.            t2_str) == 2) {
  634.       line_count = line_value;
  635.       l = strlen(t2_str);
  636.       if (t2_str[l - 1] == '"') {
  637.         t2_str[l - 1] = '\0';
  638.       }
  639.       if (t2_str[0] == '"') {
  640.         i = 1;
  641.       } else {
  642.         i = 0;
  643.       }
  644.       strcpy(errout_filename, &(t2_str[i]));
  645.     }
  646.     break;
  647.       } else if (!isspace(temp_str[i])) {
  648.     if (strncmp(&(temp_str[i]), "line", 4) != 0) break;
  649.     else {
  650.       i += 3;
  651.     }
  652.       }
  653.     }
  654.   }
  655.   return(curr_char);
  656. }
  657.  
  658. /* read and store all characters prior to end comment indicator */
  659. static void
  660. get_comment(tagon, head_str, cmt_str)
  661.   int tagon;
  662.   char head_str[], cmt_str[];
  663. {
  664.   int curr_ch;
  665.   int prev_ch = ' ';
  666.  
  667.   /* keep going until scan is complete */
  668.   if (tagon == TRUE) {
  669.     if (head_str[0] == '\0') {
  670.       /* catenate side by side comments */
  671.       comment_len -= 2;
  672.     } else {
  673.       /* insert intermediary white space and comment */
  674.       for (curr_ch = 0;
  675.        head_str[curr_ch] != '\0';
  676.        curr_ch++) {
  677.     cmt_str[comment_len++] = head_str[curr_ch];
  678.       }
  679.       cmt_str[comment_len++] = '/';
  680.       cmt_str[comment_len++] = '*';
  681.     }
  682.   } else {
  683.     comment_len = 0;
  684.   }
  685.   while ((curr_ch = getc(fpin)) != EOF) {
  686.  
  687.     /* test for end of comment */
  688.     if ((curr_ch == '/') && (prev_ch == '*')) {
  689.       cmt_str[comment_len++] = '/';
  690.       break;
  691.     }
  692.  
  693.     /* store it */
  694.     cmt_str[comment_len++] = prev_ch = curr_ch;
  695.     if (curr_ch == '\n') line_count++;
  696.   }
  697.  
  698.   /* close storage */
  699.   cmt_str[comment_len] = '\0';
  700. }
  701.  
  702. /* structure to hold definitions */
  703. typedef struct s_param {
  704.   char *name;        /* the name of the variable */
  705.   char *desc;        /* description string */
  706.   struct s_param *next;    /* pointer to the next element */
  707. } S_PARAM, *P_PARAM;
  708. P_PARAM param_list;
  709.  
  710. /* take all of the variables between the parenthesis and break them down */
  711. static int
  712. fill_param(str)
  713.   char *str;
  714. {
  715.   int paren_loc, count, i, in_word = 1, len = strlen(str);
  716.   P_PARAM last_param = NULL, param_tmp;
  717.   char tempc[MID_SIZE];
  718.  
  719.   /* initialize the list */
  720.   param_list = NULL;
  721.   paren_loc = 0;
  722.   count = 0;
  723.   tempc[0] = '\0';
  724.   for (i = 1; i < len; i++) {
  725.  
  726.     /* check for the end */
  727.     if (str[i] == ')') {
  728.       paren_loc = i;
  729.       break;
  730.     }
  731.  
  732.     /* find a variable name; check for separators */
  733.     if (str[i] == ',') {
  734.  
  735.       /* check current information */
  736.       if (in_word == 1) {
  737.     syntax_err("empty variable list encountered");
  738.     return(-1);
  739.       }
  740.       in_word = 1;
  741.  
  742.       /* store the name */
  743.       tempc[count] = '\0';
  744.       count = 0;
  745.       if ((param_tmp = (P_PARAM) malloc(sizeof(S_PARAM))) == NULL) {
  746.     fprintf(stderr, "Serious Error: Memory Allocation Failure\n");
  747.     exit(1);
  748.       }
  749.       if ((param_tmp->name =
  750.        (char *) malloc(sizeof(char) * (strlen(tempc) + 1))) == NULL) {
  751.     fprintf(stderr, "Serious Error: Out of memory\n");
  752.     exit(1);
  753.       }
  754.       strcpy(param_tmp->name, tempc);
  755.       param_tmp->next = NULL;
  756.       param_tmp->desc = NULL;
  757.       if (param_list == NULL) {
  758.     param_list = param_tmp;
  759.     last_param = param_list;
  760.       } else {
  761.     last_param->next = param_tmp;
  762.     last_param = param_tmp;
  763.       }
  764.  
  765.     } else if (str[i] == ' ') {
  766.       if (in_word == 2) {
  767.     in_word = 0;
  768.       }
  769.     } else if (id_char(str[i])) {
  770.       if (in_word == 0) {
  771.     syntax_err("invalid parameter list encountered");
  772.     return(-1);
  773.       }
  774.       in_word = 2;
  775.       tempc[count++] = str[i];
  776.     } else {
  777.       syntax_err("unable to parse the complex C code");
  778.       return(-1);
  779.     }
  780.  
  781.   }
  782.  
  783.   /* now store the last name if any was found */
  784.   if (count != 0) {
  785.  
  786.     /* store the name */
  787.     tempc[count] = '\0';
  788.     if ((param_tmp = (P_PARAM) malloc(sizeof(S_PARAM))) == NULL) {
  789.       fprintf(stderr, "Serious Error: Memory Allocation Failure\n");
  790.       exit(1);
  791.     }
  792.     if ((param_tmp->name =
  793.      (char *) malloc(sizeof(char) * (strlen(tempc) + 1))) == NULL) {
  794.       fprintf(stderr, "Serious Error: Out of memory\n");
  795.       exit(1);
  796.     }
  797.     strcpy(param_tmp->name, tempc);
  798.     param_tmp->desc = NULL;
  799.     param_tmp->next = NULL;
  800.     if (param_list == NULL) {
  801.       param_list = param_tmp;
  802.       last_param = param_list;
  803.     } else {
  804.       last_param->next = param_tmp;
  805.       last_param = param_tmp;
  806.     }
  807.   }
  808.   return(paren_loc);
  809. }
  810.  
  811. /* remove any preceding and trailing spaces */
  812. void
  813. trim_str(str)
  814.   char *str;
  815. {
  816.   register int i = 0, j = 0;
  817.   int last_space = -1;
  818.  
  819.   /* trim leading spaces */
  820.   while (isspace(str[i])) i++;
  821.  
  822.   /* shift string */
  823.   while (1) {
  824.     if ((str[j] = str[i++]) == '\0') {
  825.       break;
  826.     } else if (isspace(str[j])) {
  827.       last_space = j;
  828.     } else {
  829.       last_space = -1;
  830.     }
  831.     j++;
  832.   }
  833.  
  834.   /* now remove any trailing spaces */
  835.   if (last_space != -1) {
  836.     str[last_space] = '\0';
  837.   }
  838. }
  839.  
  840. /* just go through and send out the entire parameter list */
  841. static int
  842. oldc_output()
  843. {
  844.   int count = 0, lcount = 0;
  845.   P_PARAM param_tmp;
  846.  
  847.   /* first test for the simple case */
  848.   if (param_list == NULL) {
  849.     strcpy(dummy_str, "void");
  850.     return(4);
  851.   }
  852.   dummy_str[0] = '\0';
  853.  
  854.   /* go through the list */
  855.   while (param_list != NULL) {
  856.  
  857.     /* add in separators */
  858.     if (count++ > 0) {
  859.  
  860.       strcat(dummy_str, ", ");
  861.       lcount += 2;
  862.  
  863.     }
  864.  
  865.     /* check the type */
  866.     if (param_list->desc != NULL) {
  867.       trim_str(param_list->desc);
  868.       strcat(dummy_str, param_list->desc);
  869.       lcount += strlen(param_list->desc);
  870.       free(param_list->desc);
  871.     } else {
  872.       if (get_option(OPT_NONAMES)) {
  873.     strcat(dummy_str, "int");
  874.     lcount += 3;
  875.       } else if (strcmp("int", param_list->name)) {
  876.     strcat(dummy_str, "int ");
  877.     strcat(dummy_str, param_list->name);
  878.     lcount += 4 + strlen(param_list->name);
  879.       } else {
  880.     strcat(dummy_str, param_list->name);
  881.     lcount += strlen(param_list->name);
  882.       }
  883.     }
  884.     free(param_list->name);
  885.  
  886.     /* clean up storage */
  887.     param_tmp = param_list;
  888.     param_list = param_list->next;
  889.     param_tmp->next = NULL;
  890.     free(param_tmp);
  891.  
  892.   }
  893.  
  894.   /* finish it up */
  895.   return(lcount);
  896. }
  897.  
  898. /* return the proper element */
  899. static P_PARAM
  900. var_match(str)
  901.   char *str;
  902. {
  903.   int i, len, len2;
  904.   P_PARAM p_hold;
  905.  
  906.   /* go through all of the items and find a match */
  907.   len2 = strlen(str);
  908.   p_hold = param_list;
  909.   while (p_hold != NULL) {
  910.  
  911.     /* check for a match */
  912.     len = strlen(p_hold->name);
  913.     for (i = 0; i < len2 - len + 1; i++) {
  914.       /* check for the match */
  915.       if (strncmp(str + i, p_hold->name, len) == 0) {
  916.     /* found a match */
  917.     if (!id_char(str[i + len])) {
  918.       return(p_hold);
  919.     }
  920.       } else if (id_char(str[i])) {
  921.     /* definite non-match */
  922.     i = len2 - len + 1;
  923.       }
  924.     }
  925.  
  926.     /* go to the next element */
  927.     p_hold = p_hold->next;
  928.   }
  929.  
  930.   return(p_hold);
  931. }
  932.  
  933. /* remove the variable name from the given type and variable combo */
  934. static void
  935. kill_variable(str)
  936.   char *str;
  937. {
  938.   register int i;
  939.  
  940.   /* no need to breakdown this baby */
  941.   if (strcmp(str, "...") == 0) return;
  942.  
  943.   /* search for the variable name */
  944.   trim_str(str);
  945.   for (i = strlen(str) - 1; i >= 0; i--) {
  946.  
  947.     /* found it */
  948.     if (id_char(str[i])) {
  949.  
  950.       /* clean it up */
  951.       while ((i >= 0) &&
  952.          id_char(str[i])) {
  953.     str[i--] = ' ';
  954.       }
  955.       i++;
  956.       trim_str(str + i);
  957.       if (i == 0) {
  958.     strcpy(str, "int");
  959.       } else {
  960.     trim_str(str);
  961.       }
  962.       break;
  963.  
  964.     }
  965.  
  966.   }
  967. }
  968.  
  969. /* separate and rebuild the ANSI format list */
  970. static int
  971. newc_parse (i_str)
  972.   char *i_str;
  973. {
  974.   char hold_str[MID_SIZE], hold2_str[MID_SIZE];
  975.   P_SUBST sub_tmp;
  976.   int depth, cnt = 0, len, i;
  977.  
  978.   /* start the process */
  979.   dummy_str[0] = '\0';
  980.   do {
  981.  
  982.     /* move along the input string */
  983.     switch (*i_str) {
  984.     case ',':
  985.     case '\0':
  986.       /* finish off this item */
  987.       if (cnt == 0) break;
  988.       hold_str[cnt] = '\0';
  989.  
  990.       /* search for matches among the replacement code */
  991.       for (sub_tmp = subst_list;
  992.        sub_tmp != NULL;
  993.        sub_tmp = sub_tmp->next) {
  994.  
  995.     /* check for usage */
  996.     if ((sub_tmp->usewhen != 2) &&
  997.         (sub_tmp->usewhen != (doc_extract != DOC_NONE))) continue;
  998.  
  999.     /* check it */
  1000.     len = strlen(sub_tmp->from_str);
  1001.     switch (sub_tmp->submode) {
  1002.     case SUBST_FULL:
  1003.       /* the full string needs replacing? */
  1004.       if (strcmp(hold_str, sub_tmp->from_str) == 0) {
  1005.         strcpy(hold_str, sub_tmp->to_str);
  1006.       }
  1007.       break;
  1008.     case SUBST_TYPE:
  1009.       /* the type only needs replacing? */
  1010.       if (strncmp(hold_str, sub_tmp->from_str, len) == 0) {
  1011.         strcpy(hold2_str, hold_str + len);
  1012.         strcpy(hold_str, sub_tmp->to_str);
  1013.         strcat(hold_str, hold2_str);
  1014.       }
  1015.       break;
  1016.     case SUBST_NAME:
  1017.       /* the variable only needs replacing? WHY!? */
  1018.       if ((cnt > len) &&
  1019.           (strcmp(hold_str + cnt - len, sub_tmp->from_str) == 0)) {
  1020.         hold_str[cnt - len] = '\0';
  1021.         strcat(hold_str, sub_tmp->to_str);
  1022.       }
  1023.       break;
  1024.     }
  1025.       }
  1026.  
  1027.       /* check for removal of register type */
  1028.       if (strncmp(hold_str, "register ", 9) == 0) {
  1029.     for (i = 0; i < 9; i++) {
  1030.       hold_str[i] = ' ';
  1031.     }
  1032.       }
  1033.  
  1034.       /* do we clean it? */
  1035.       if (get_option(OPT_NONAMES)) {
  1036.     kill_variable(hold_str);
  1037.       } else {
  1038.     trim_str(hold_str);
  1039.       }
  1040.  
  1041.       /* append to output */
  1042.       if (dummy_str[0] != '\0') {
  1043.     strcat(dummy_str, ", ");
  1044.       }
  1045.       strcat(dummy_str, hold_str);
  1046.       cnt = 0;
  1047.       break;
  1048.     case '{':
  1049.       /* collect up all of the type declaration */
  1050.       depth = -1;
  1051.       do {
  1052.     hold_str[cnt++] = *i_str;
  1053.     switch (*i_str) {
  1054.     case '\0':
  1055.       syntax_err("unexpected end of parameters");
  1056.       return(-1);
  1057.     case '{':
  1058.       depth++;
  1059.       break;
  1060.     case '}':
  1061.       depth--;
  1062.       break;
  1063.     default:
  1064.       /* ignore me */
  1065.       break;
  1066.     }
  1067.     i_str++;
  1068.       } while ((depth > 0) ||
  1069.            (*i_str != '}'));
  1070.       hold_str[cnt++] = *i_str;
  1071.       break;
  1072.     case ' ':
  1073.       if (cnt == 0) break;
  1074.     default:
  1075.       /* just copy it */
  1076.       hold_str[cnt++] = *i_str;
  1077.     }
  1078.  
  1079.   } while (*(i_str++) != '\0');
  1080.  
  1081.   /* give back the length */
  1082.   return(strlen(dummy_str));
  1083. }
  1084.  
  1085. /* extract all of the parameters using old style format */
  1086. static int
  1087. oldc_parse(str)
  1088.   char *str;
  1089. {
  1090.   int depth = 0, last_char = ')';
  1091.   int start, count2, in_var;
  1092.   P_PARAM p_tmp;
  1093.   P_SUBST sub_tmp;
  1094.  
  1095.   char type_name[MID_SIZE], var_name[MID_SIZE];
  1096.   char oldvar_name[MID_SIZE], tempc[MID_SIZE];
  1097.  
  1098.   /* build the parameter list */
  1099.   if ((start = fill_param(str)) == -1) {
  1100.     /* clean up and exit on error */
  1101.     while (param_list != NULL) {
  1102.       p_tmp = param_list;
  1103.       param_list = param_list->next;
  1104.       p_tmp->next = NULL;
  1105.       free(p_tmp);
  1106.     }
  1107.     return(-1);
  1108.   }
  1109.   if (str[start] != ')') {
  1110.     strcpy(dummy_str, "void");
  1111.     return(4);
  1112.   }
  1113.  
  1114.   /* begin with non-space character */
  1115.   for (str += start + 1; *str == ' '; str++) ;
  1116.   count2 = 0;
  1117.   in_var = FALSE;
  1118.   type_name[0] = '\0';
  1119.  
  1120.   /* now go through the entire structure */
  1121.   for (; *str != '\0'; str++) {
  1122.  
  1123.     switch (*str) {
  1124.     case ' ':
  1125.       /* add on to variable or append to type definition */
  1126.       if (in_var == TRUE) {
  1127.     var_name[count2++] = ' ';
  1128.     break;
  1129.       }
  1130.       break;
  1131.     case '{':
  1132.       /* must be a struct declaration */
  1133.       if ((depth != 0) ||
  1134.       (in_var == TRUE)) {
  1135.     syntax_err("unexpected left brace encountered");
  1136.     return(-1);
  1137.       }
  1138.       depth = -1;
  1139.       if (var_name[count2] != ' ') {
  1140.     var_name[count2++] = ' ';
  1141.       }
  1142.       do {
  1143.     var_name[count2++] = *str;
  1144.     switch (*str) {
  1145.     case '\0':
  1146.       syntax_err("unable to parse the complex C structure");
  1147.       return(-1);
  1148.     case '{':
  1149.       depth++;
  1150.       break;
  1151.     case '}':
  1152.       depth--;
  1153.       break;
  1154.     default:
  1155.       /* ignore me */
  1156.       break;
  1157.     }
  1158.     str++;
  1159.       } while ((depth > 0) ||
  1160.            (*str != '}'));
  1161.       goto saw_space;
  1162.       break;
  1163.     case ',':
  1164.       /* just add on if between parenthesis */
  1165.       if (depth != 0) {
  1166.     var_name[count2++] = ',';
  1167.     break;
  1168.       }
  1169.     case ';':
  1170.       /* found end of declaration? */
  1171.       var_name[count2] = '\0';
  1172.       if ((depth != 0) || (type_name[0] == '\0')) {
  1173.     syntax_err("unable to parse the complex C structure");
  1174.     return(-1);
  1175.       }
  1176.       if (var_name[0] == '\0') {
  1177.     syntax_err("unable to parse the complex C structure");
  1178.     return(-1);
  1179.       }
  1180.  
  1181.       /* build the proper string */
  1182.       trim_str(type_name);
  1183.       strcpy(tempc, type_name);
  1184.       strcat(tempc, " ");
  1185.       trim_str(var_name);
  1186.       strcpy(oldvar_name, var_name);
  1187.       strcat(tempc, var_name);
  1188.  
  1189.       /* search for matches among the replacement code */
  1190.       for (sub_tmp = subst_list;
  1191.        sub_tmp != NULL;
  1192.        sub_tmp = sub_tmp->next) {
  1193.     /* check it */
  1194.     switch (sub_tmp->submode) {
  1195.     case SUBST_FULL:
  1196.       /* the full string needs replacing? */
  1197.       if (strcmp(tempc, sub_tmp->from_str) == 0) {
  1198.         strcpy(tempc, sub_tmp->to_str);
  1199.       }
  1200.       break;
  1201.     case SUBST_TYPE:
  1202.       /* the type only needs replacing? */
  1203.       if (strcmp(type_name, sub_tmp->from_str) == 0) {
  1204.         strcpy(tempc, sub_tmp->to_str);
  1205.         strcpy(type_name, sub_tmp->to_str);
  1206.         strcat(tempc, " ");
  1207.         strcat(tempc, var_name);
  1208.       }
  1209.       break;
  1210.     case SUBST_NAME:
  1211.       /* the variable only needs replacing? WHY!? */
  1212.       if (strcmp(var_name, sub_tmp->from_str) == 0) {
  1213.         strcpy(tempc, type_name);
  1214.         strcat(tempc, " ");
  1215.         strcat(tempc, sub_tmp->to_str);
  1216.         strcpy(var_name, sub_tmp->to_str);
  1217.       }
  1218.       break;
  1219.     }
  1220.       }
  1221.  
  1222.       /* now find the proper variable name */
  1223.       if ((p_tmp = var_match(oldvar_name)) == NULL) {
  1224.     char temp_str[MID_SIZE];
  1225.     sprintf(temp_str, "could not place variable %s properly",
  1226.         oldvar_name);
  1227.     syntax_err(temp_str);
  1228.     return(-1);
  1229.       }
  1230.  
  1231.       /* now check for variable name removal */
  1232.       if (get_option(OPT_NONAMES)) {
  1233.     kill_variable(tempc);
  1234.       }
  1235.  
  1236.       /* set aside space */
  1237.       if ((p_tmp->desc =
  1238.        (char *) malloc(sizeof(char) * (strlen(tempc) + 1))) == NULL) {
  1239.     fprintf(stderr, "Serious Memory Allocation Error\n");
  1240.     exit(1);
  1241.       }
  1242.  
  1243.       /* now stow it */
  1244.       strcpy(p_tmp->desc, tempc);
  1245.  
  1246.       /* reset properly */
  1247.       count2 = 0;
  1248.       var_name[0] = '\0';
  1249.       if (*str == ';') {
  1250.     in_var = FALSE;
  1251.     type_name[0] = '\0';
  1252.       }
  1253.       break;
  1254.     case '*':
  1255.       /* just append on, must now be in variable */
  1256.       if ((last_char == ' ') && (in_var == FALSE)) {
  1257.     in_var = TRUE;
  1258.     goto saw_space;
  1259.       } else if (in_var == FALSE) {
  1260.     /* must push out type properly */
  1261.     var_name[count2] = '\0';
  1262.     count2 = 0;
  1263.     if ((type_name[0] != '\0') &&
  1264.         (type_name[strlen(type_name) - 1] != ' '))  {
  1265.       strcat(type_name, " ");
  1266.     }
  1267.     if ((type_name[0] != '\0') ||
  1268.         (strcmp(var_name, "register") != 0)) {
  1269.       strcat(type_name, var_name);
  1270.     }
  1271.     var_name[0] = '\0';
  1272.       }
  1273.       in_var = TRUE;
  1274.       var_name[count2++] = '*';
  1275.       break;
  1276.     case '(':
  1277.     case '[':
  1278.       /* count depth, assume balanced for both */
  1279.       depth++;
  1280.       if ((last_char == ' ') &&
  1281.       (in_var == FALSE)) {
  1282.     in_var = TRUE;
  1283.     goto saw_space;
  1284.       }
  1285.       in_var = TRUE;
  1286.       var_name[count2++] = *str;
  1287.       break;
  1288.     case ')':
  1289.     case ']':
  1290.       /* check depth */
  1291.       depth--;
  1292.       if (depth < 0) {
  1293.     syntax_err("misbalanced parenthesis encountered");
  1294.     return(-1);
  1295.       }
  1296.       if (last_char == ' ') goto saw_space;
  1297.       var_name[count2++] = *str;
  1298.       break;
  1299.     default:
  1300.       if (!id_char(*str) && (depth == 0)) {
  1301.     syntax_err("unknown variable structure encountered");
  1302.     return(-1);
  1303.       }
  1304.       /* check for just seeing space */
  1305.       if (last_char == ' ' && in_var == FALSE) {
  1306.  
  1307.       saw_space:
  1308.     var_name[count2] = '\0';
  1309.     count2 = 0;
  1310.     if ((type_name[0] != '\0') &&
  1311.         (type_name[strlen(type_name) - 1] != ' '))  {
  1312.       strcat(type_name, " ");
  1313.     }
  1314.     if ((type_name[0] != '\0') ||
  1315.         (strcmp(var_name, "register") != 0)) {
  1316.       strcat(type_name, var_name);
  1317.     }
  1318.     var_name[0] = '\0';
  1319.  
  1320.       }
  1321.       var_name[count2++] = *str;
  1322.       break;
  1323.     }
  1324.  
  1325.     /* save the last character */
  1326.     last_char = *str;
  1327.   }
  1328.  
  1329.   /* now send everything out */
  1330.   return(oldc_output());
  1331. }
  1332.  
  1333. /* function to determine if the parameter list is K&R, ANSI or empty */
  1334. static int
  1335. diverge_style(str, len)
  1336.   char *str;
  1337.   int len;
  1338. {
  1339.   int void_fnd = FALSE, nspc_fnd = FALSE, in_word = 1;
  1340.  
  1341.   /* perform the first simple test */
  1342.   if (str[len - 1] == ';') return(2);
  1343.  
  1344.   /* should have a right parenthesis now  */
  1345.   if (str[len - 1] != ')') {
  1346.     fprintf(stderr, "Expecting right paren in file %s\n", file_name);
  1347.     return(1);
  1348.   }
  1349.  
  1350.   /* now check to see if it only lists all variables */
  1351.   for (str++; *str != '\0'; str++) {
  1352.  
  1353.     /* check for separators */
  1354.     switch (*str) {
  1355.     case ',':
  1356.       /* variable separator */
  1357.       if (in_word == 1) {
  1358.     fprintf(stderr, "Empty variable list in file %s", file_name);
  1359.     return(1);
  1360.       }
  1361.       nspc_fnd = TRUE;
  1362.       in_word = 1;
  1363.       break;
  1364.     case ' ':
  1365.       /* word separator */
  1366.       if (in_word == 2) {
  1367.     in_word = 0;
  1368.       }
  1369.       break;
  1370.     case ')':
  1371.       if (*(str + 1) != '\0') {
  1372.     return(1);
  1373.       }
  1374.       break;
  1375.     default:
  1376.       /* check for variable name */
  1377.       if ((void_fnd == FALSE) &&
  1378.       (strncmp(str, "void", 4) == 0)) {
  1379.     void_fnd = TRUE;
  1380.     str += 3;
  1381.     in_word = 2;
  1382.       } else if (id_char(*str)) {
  1383.     if (in_word == 0) {
  1384.       return(1);
  1385.     }
  1386.     in_word = 2;
  1387.     nspc_fnd = TRUE;
  1388.       } else {
  1389.     return(1);
  1390.       }
  1391.       break;
  1392.     }
  1393.   }
  1394.   return((nspc_fnd == TRUE)? 2 : 0);
  1395. }
  1396.  
  1397. /* return length of function name... and store it in space provide */
  1398. static int
  1399. find_name(out_name, in_desc, desc_len)
  1400.   char *out_name, *in_desc;
  1401.   int desc_len;
  1402. {
  1403.   int pos, count = 0;
  1404.  
  1405.   /* find the end of the name */
  1406.   for (pos = desc_len; pos > 0; pos--) {
  1407.     if (id_char(in_desc[pos])) break;
  1408.   }
  1409.  
  1410.   /* find the length of the name */
  1411.   while ((pos > 0) &&
  1412.      (id_char(in_desc[pos]))) {
  1413.     count++;
  1414.     pos--;
  1415.   }
  1416.  
  1417.   /* copy it */
  1418.   if (!id_char(in_desc[pos])) {
  1419.     pos++;
  1420.   } else {
  1421.     count++;
  1422.   }
  1423.   strncpy(out_name, in_desc + pos, count);
  1424.   out_name[count] = '\0';
  1425.   return(count);
  1426. }
  1427.  
  1428. /* function to extract the function prototype from preceding characters */
  1429. static void
  1430. parse_func()
  1431. {
  1432.   P_SUBST sub_tmp;
  1433.   P_PROTO tmp_proto;
  1434.   int count, valid = TRUE, depth = 0, done = FALSE;
  1435.   int sep_point = 0, typelen, cmpstt, len, dummy_len = 0;
  1436.   char *func_declare, *func_list, name_space[MID_SIZE];
  1437.  
  1438.   /* clean up the input string */
  1439.   trim_str(code_info);
  1440.   len = strlen(code_info);
  1441.  
  1442.   /* now go backwards and find the first occurance */
  1443.   /* of a right parenthesis without a '[', ',' or ';' after */
  1444.   for (count = len - 1; done == FALSE && count > 0; count--) {
  1445.  
  1446.     /* check for a select group of characters */
  1447.     switch (code_info[count]) {
  1448.     case ' ':
  1449.       /* don't change validity for spaces */
  1450.       break;
  1451.     case ')':
  1452.       /* check if it is a good match */
  1453.       depth++;
  1454.       if (depth == 1 && valid == TRUE) {
  1455.     done = TRUE;
  1456.       }
  1457.       break;
  1458.     case '(':
  1459.       /* keep proper track of depth */
  1460.       depth--;
  1461.       if (depth < 0) {
  1462.     syntax_err("too many left parenthesis encountered");
  1463.     break;
  1464.       }
  1465.  
  1466.       /* watch for function pointers */
  1467.       valid = FALSE;
  1468.       break;
  1469.     case '[':
  1470.     case ';':
  1471.     case ',':
  1472.       /* any paranthesis before this is invalid */
  1473.       valid = FALSE;
  1474.       break;
  1475.     case '=':
  1476.       /* there should be no equal signs anywhere around this */
  1477.       valid = FALSE;
  1478.       count = 0;
  1479.       break;
  1480.     default:
  1481.       /* it can now be a valid parenthesis */
  1482.       valid = TRUE;
  1483.       break;
  1484.     }
  1485.   }
  1486.  
  1487.   /* get out if no function type was found */
  1488.   if (done != TRUE) return;
  1489.  
  1490.   /* now find the separation point for the function */
  1491.   done = FALSE;
  1492.   for (; done == FALSE && count > 0; count--) {
  1493.     valid = code_info[count];
  1494.     switch (valid) {
  1495.     case ' ':
  1496.       break;
  1497.     case ')':
  1498.       /* go deeper */
  1499.       depth++;
  1500.       break;
  1501.     case '(':
  1502.       /* rise higher */
  1503.       depth--;
  1504.       if (depth == 0) {
  1505.     sep_point = count;
  1506.     done = TRUE;
  1507.       }
  1508.       break;
  1509.     default:
  1510.       break;
  1511.     }
  1512.   }
  1513.  
  1514.   /* confirm separation point */
  1515.   if (done == FALSE) {
  1516.     syntax_err("too many right parenthesis encountered");
  1517.     return;
  1518.   }
  1519.  
  1520.   /* now find the start of the function declaration */
  1521.   for (; count > 0; count--) {
  1522.     if ((code_info[count] == ';') ||
  1523.     (code_info[count] == '}')) break;
  1524.     if (code_info[count] == '(') {
  1525.       syntax_err("unexpected left parenthesis found while parsing parameters");
  1526.       return;
  1527.     }
  1528.   }
  1529.   if ((code_info[count] == ';') ||
  1530.       (code_info[count] == '}')) count++;
  1531.  
  1532.   /* gain space */
  1533.   if ((func_list = (char *) malloc(sizeof(char) * (len - sep_point + 1)))
  1534.       == NULL) {
  1535.     fprintf(stderr, "Serious Error: Malloc failed\n");
  1536.     exit(1);
  1537.   }
  1538.   if ((func_declare =
  1539.        (char *) malloc(sizeof(char) * (sep_point - count + 1))) == NULL) {
  1540.     fprintf(stderr, "Serious Error: Malloc failed\n");
  1541.     exit(1);
  1542.   }
  1543.  
  1544.   /* now assign the locations */
  1545.   strcpy(func_list, &(code_info[sep_point]));
  1546.   strncpy(func_declare, &(code_info[count]), sep_point - count);
  1547.   func_declare[sep_point - count] = '\0';
  1548.   trim_str(func_list);
  1549.   trim_str(func_declare);
  1550.  
  1551.   /* find just the function name */
  1552.   len = strlen(func_declare);
  1553.   count = find_name(name_space, func_declare, len);
  1554.  
  1555.   /* just leave if there is no function */
  1556.   if (count == 0) {
  1557.     free(func_list);
  1558.     free(func_declare);
  1559.     return;
  1560.   }
  1561.  
  1562.   /* check for statics which shouldn't be shown */
  1563.   if (get_option(OPT_STATICMODE) != ANY_STATICS) {
  1564.     if (!strncmp(func_declare, "static ", 7) ==
  1565.     (get_option(OPT_STATICMODE) == NO_STATICS)) {
  1566.       last_comment[0] = '\0';
  1567.       comment_len = 0;
  1568.       free(func_list);
  1569.       free(func_declare);
  1570.       return;
  1571.     }
  1572.   }
  1573.  
  1574.   /* declare storage space for the function */
  1575.   if ((tmp_proto = (P_PROTO) malloc(sizeof(S_PROTO))) == NULL) {
  1576.     fprintf(stderr, "Memory allocation failure\n");
  1577.     exit(1);
  1578.   }
  1579.   tmp_proto->next = NULL;
  1580.   tmp_proto->name = NULL;
  1581.   tmp_proto->ftype = NULL;
  1582.   tmp_proto->fname = NULL;
  1583.   tmp_proto->plist = NULL;
  1584.   tmp_proto->comment = NULL;
  1585.  
  1586.   /* place it in the list */
  1587.   if ((proto_next == NULL) || (proto_list == NULL)) {
  1588.     proto_next = proto_list = tmp_proto;
  1589.   } else {
  1590.     proto_next->next = tmp_proto;
  1591.     proto_next = tmp_proto;
  1592.   }
  1593.   if ((proto_next->fname =
  1594.        (char *) malloc(sizeof(char) * (strlen(file_name) + 2))) == NULL) {
  1595.     fprintf(stderr, "Memory allocation error\n");
  1596.     exit(1);
  1597.   }
  1598.   strcpy(proto_next->fname, file_name);
  1599.  
  1600.   /* now copy any preceding comments if desired */
  1601.   if (get_option(OPT_COMMENTS) &&
  1602.       (last_comment[0] != '\0')) {
  1603.     if ((proto_next->comment =
  1604.      (char *) malloc(sizeof(char) * (comment_len + 5))) == NULL) {
  1605.       fprintf(stderr, "Memory allocation error\n");
  1606.       exit(1);
  1607.     }
  1608.     strcpy(proto_next->comment, "/*");
  1609.     strcat(proto_next->comment, last_comment);
  1610.     last_comment[0] = '\0';
  1611.     comment_len = 0;
  1612.   } else {
  1613.     proto_next->comment = NULL;
  1614.   }
  1615.  
  1616.   /* check for the conversion of the type declaration */
  1617.   if (count != len) {
  1618.     if (strncmp("extern ", func_declare, 7) == 0) {
  1619.       cmpstt = 7;
  1620.     } else {
  1621.       cmpstt = 0;
  1622.     }
  1623.     for (sub_tmp = subst_list;
  1624.      sub_tmp != NULL;
  1625.      sub_tmp = sub_tmp->next) {
  1626.       /* check it */
  1627.       if (sub_tmp->submode == SUBST_TYPE) {
  1628.  
  1629.     /* compare */
  1630.     typelen = strlen(sub_tmp->from_str);
  1631.     if (strncmp(func_declare + cmpstt, sub_tmp->from_str, typelen) == 0) {
  1632.       strcpy(tmp_str, sub_tmp->to_str);
  1633.       strcat(tmp_str, func_declare + cmpstt + typelen);
  1634.       strcpy(func_declare, tmp_str);
  1635.       len += (strlen(sub_tmp->to_str) - typelen - cmpstt);
  1636.     }
  1637.  
  1638.       }
  1639.     }
  1640.   }
  1641.  
  1642.   /* output extern if desired */
  1643.   if (get_option(OPT_EXTERNS) &&
  1644.       strncmp("extern ", func_declare, 7) != 0) {
  1645.     strcpy(dummy_str, "extern ");
  1646.     dummy_len = 7;
  1647.   } else {
  1648.     dummy_str[0] = '\0';
  1649.     dummy_len = 0;
  1650.   }
  1651.  
  1652.   /* now check if the function type is an integer */
  1653.   if (count == len) {
  1654.     strcat(dummy_str, "int ");
  1655.     strcat(dummy_str, func_declare);
  1656.     dummy_len += 4 + len;
  1657.   } else {
  1658.     strcat(dummy_str, func_declare);
  1659.     dummy_len += len;
  1660.   }
  1661.  
  1662.   /* store the function header */
  1663.   if ((proto_next->ftype =
  1664.        (char *) malloc(sizeof(char) * (dummy_len + 2))) == NULL) {
  1665.     fprintf(stderr, "Memory allocation error\n");
  1666.     exit(1);
  1667.   }
  1668.   strcpy(proto_next->ftype, dummy_str);
  1669.  
  1670.   /* the function string */
  1671.   if ((proto_next->name =
  1672.        (char *) malloc(sizeof(char) * (count + 2))) == NULL) {
  1673.     fprintf(stderr, "Memory allocation error\n");
  1674.     exit(1);
  1675.   }
  1676.   strcpy(proto_next->name, name_space);
  1677.  
  1678.   /* now output empty list amount */
  1679.   len = strlen(func_list);
  1680.   switch (diverge_style(func_list, len)) {
  1681.   case 0:
  1682.     /* empty or "void" parameter list */
  1683.     strcpy(dummy_str, "void");
  1684.     dummy_len = 4;
  1685.     break;
  1686.   case 1:
  1687.     /* ANSI C format! -- remove trailing parenthesis */
  1688.     func_list[--len] = '\0';
  1689.     if ((dummy_len = newc_parse(func_list + 1)) == -1) {
  1690.       free(func_list);
  1691.       free(func_declare);
  1692.       pop_proto();
  1693.       return;
  1694.     }
  1695.     break;
  1696.   default:
  1697.     /* K&R C format */
  1698.     if ((dummy_len = oldc_parse(func_list)) == -1) {
  1699.       free(func_list);
  1700.       free(func_declare);
  1701.       pop_proto();
  1702.       return;
  1703.     }
  1704.     break;
  1705.   }
  1706.  
  1707.   /* store it */
  1708.   if ((proto_next->plist =
  1709.        (char *) malloc(sizeof(char) * (dummy_len + 2))) == NULL) {
  1710.     fprintf(stderr, "Memory allocation error\n");
  1711.     exit(1);
  1712.   }
  1713.   strcpy(proto_next->plist, dummy_str);
  1714.  
  1715.   /* replace space */
  1716.   free(func_list);
  1717.   free(func_declare);
  1718. }
  1719.  
  1720. /* go through the file extracting functions */
  1721. void
  1722. parse_file()
  1723. {
  1724.   int curr_char, count = 0, was_comment = FALSE, may_flush = FALSE;
  1725.   int depth = 0, num_comment = 0, temp_count = 0, temp_lines = 0;
  1726.   char temp_list[MID_SIZE];
  1727.   int prev_char = '\n', old_prev_real = ' ', prev_real = ' ';
  1728.  
  1729.   /* go to it */
  1730.   start_comment[0] = '\0';
  1731.   last_comment[0] = '\0';
  1732.   temp_list[0] = '\0';
  1733.   while ((curr_char = getc(fpin)) != EOF) {
  1734.  
  1735.     /* check depth first */
  1736.     if (curr_char == '\n') line_count++;
  1737.     if (depth == 0) {
  1738.  
  1739.       /* process the characters */
  1740.       if (curr_char == '#' && prev_char == '\n') {
  1741.  
  1742.     /* nuke any preprocessor statements */
  1743.     was_comment = FALSE;
  1744.     prev_char = '#';
  1745.     curr_char = preprocessor_check();
  1746.  
  1747.       } else if (curr_char == '"') {
  1748.  
  1749.     /* nuke string quotes -- must be on same line */
  1750.     prev_char = curr_char;
  1751.     count = 0;
  1752.     while (!feof(fpin)) {
  1753.       if ((curr_char = getc(fpin)) == '"') {
  1754.         break;
  1755.       } else if (curr_char == '\n') {
  1756.         syntax_err("unexpected newline found in string");
  1757.         line_count++;
  1758.       } else if (curr_char == '\\') {
  1759.         prev_char = curr_char;
  1760.         curr_char = getc(fpin);
  1761.       }
  1762.       prev_char = curr_char;
  1763.     }
  1764.  
  1765.       } else if (curr_char == '\'') {
  1766.  
  1767.     /* nuke character quotes -- must be on same line */
  1768.     count = 0;
  1769.     prev_char = curr_char;
  1770.     while (!feof(fpin)) {
  1771.       if ((curr_char = getc(fpin)) == '\'') {
  1772.         break;
  1773.       } else if (curr_char == '\n') {
  1774.         syntax_err("unexpected newline in character constant");
  1775.         line_count++;
  1776.       } else if (curr_char == '\\') {
  1777.         prev_char = curr_char;
  1778.         curr_char = getc(fpin);
  1779.       }
  1780.       prev_char = curr_char;
  1781.     }
  1782.  
  1783.       } else if (curr_char == '*' && prev_char == '/') {
  1784.  
  1785.     /* clear out commments; treat as spaces */
  1786.     if (count > 0) count--;
  1787.     if (was_comment == FALSE) {
  1788.       num_comment++;
  1789.       temp_count = 0;
  1790.     } else {
  1791.       temp_count--;
  1792.       if ((get_option(OPT_SINGLECOMMENTS) == TRUE) &&
  1793.           (temp_count > 0)) {
  1794.         num_comment++;
  1795.         was_comment = FALSE;
  1796.         temp_count = 0;
  1797.       }
  1798.     }
  1799.     temp_list[temp_count] = '\0';
  1800.     curr_char = ' ';
  1801.     if (get_option(OPT_COMMENTS) ||
  1802.         ((num_comment == 1) &&
  1803.          get_option(OPT_FIRSTCOMMENT))) {
  1804.  
  1805.       /* process it */
  1806.       if (num_comment == 1) {
  1807.         get_comment(was_comment, temp_list, start_comment);
  1808.       } else {
  1809.         get_comment(was_comment, temp_list, last_comment);
  1810.       }
  1811.       was_comment = TRUE;
  1812.       temp_lines = 0;
  1813.       temp_count = (-1);
  1814.  
  1815.     } else {
  1816.  
  1817.       while ((curr_char = getc(fpin)) != EOF) {
  1818.  
  1819.         /* test for end of comment */
  1820.         if (curr_char == '\n') line_count++;
  1821.         if ((curr_char == '/') && (prev_char == '*')) {
  1822.           break;
  1823.         }
  1824.         prev_char = curr_char;
  1825.       }
  1826.       curr_char = ' ';
  1827.  
  1828.     }
  1829.     prev_real = old_prev_real;
  1830.  
  1831.       } else if ((curr_char == '/') && (prev_char == '/')) {
  1832.  
  1833.     /* just yank out any C++ comments */
  1834.     if (count > 0) count--;
  1835.     while ((curr_char = getc(fpin)) != EOF) {
  1836.  
  1837.       /* test for end of comment */
  1838.       if (curr_char == '\n') {
  1839.         line_count++;
  1840.         break;
  1841.       }
  1842.       prev_char = curr_char;
  1843.  
  1844.     }
  1845.     curr_char = ' ';
  1846.     prev_real = old_prev_real;
  1847.  
  1848.       } else if (curr_char == '{') {
  1849.  
  1850.     /* reset recording process */
  1851.     was_comment = FALSE;
  1852.     may_flush = FALSE;
  1853.     depth++;
  1854.  
  1855.     /* now check if it is a function */
  1856.     if ((prev_real == ';') ||
  1857.         (prev_real == ')')) {
  1858.  
  1859.       /* found end of function, struct, or union definition */
  1860.       code_info[count] = '\0';
  1861.       parse_func();
  1862.       code_info[count = 0] = '\0';
  1863.  
  1864.     } else {
  1865.       code_info[count++] = '{';
  1866.     }
  1867.  
  1868.       } else if (curr_char == '}') {
  1869.  
  1870.     syntax_err("extra right brace encountered");
  1871.     break;
  1872.  
  1873.       }
  1874.  
  1875.       /* tag onto the list */
  1876.       if (depth == 0) {
  1877.  
  1878.     /* store the characters for later use */
  1879.     if (isspace(curr_char) &&
  1880.         (count != 0 && code_info[count - 1] != ' ')) {
  1881.  
  1882.       /* combine any white space into a single space character */
  1883.       code_info[count++] = ' ';
  1884.  
  1885.     } else if (!isspace(curr_char)) {
  1886.  
  1887.       /* store any other type directly */
  1888.       if (curr_char != '/') {
  1889.         was_comment = FALSE;
  1890.         temp_count = 0;
  1891.         temp_lines = 0;
  1892.       }
  1893.       code_info[count++] = curr_char;
  1894.       old_prev_real = prev_real;
  1895.       prev_real = curr_char;
  1896.  
  1897.     }
  1898.  
  1899.     /* count the lead in */
  1900.     if (was_comment == TRUE) {
  1901.  
  1902.       /* no multiple newlines */
  1903.       if (curr_char == '\n') {
  1904.         if (temp_lines == 0) {
  1905.           temp_lines = 1;
  1906.         } else {
  1907.           temp_lines = 0;
  1908.           temp_count = -1;
  1909.           was_comment = FALSE;
  1910.         }
  1911.       }
  1912.  
  1913.       /* check beginning */
  1914.       if (temp_count >= 0) {
  1915.         temp_list[temp_count] = curr_char;
  1916.       }
  1917.       temp_count++;
  1918.  
  1919.     }
  1920.  
  1921.     /* now note what was last encountered */ 
  1922.     prev_char = curr_char;
  1923.  
  1924.       }
  1925.  
  1926.     } else {
  1927.  
  1928.       /* keep track of depth and got through code otherwise */
  1929.       if (curr_char == '#' && prev_char == '\n') {
  1930.  
  1931.     /* nuke any preprocessor statements */
  1932.     prev_char = '#';
  1933.     curr_char = preprocessor_check();
  1934.  
  1935.       } else if (curr_char == '"') {
  1936.  
  1937.     /* nuke string quotes -- must be on same line */
  1938.     may_flush = TRUE;
  1939.     while (!feof(fpin)) {
  1940.       prev_char = curr_char;
  1941.       if ((curr_char = getc(fpin)) == '\n') {
  1942.         syntax_err("unexpected newline found in string");
  1943.         line_count++;
  1944.       } else if (curr_char == '\\') {
  1945.         prev_char = curr_char;
  1946.         curr_char = getc(fpin);
  1947.         continue;
  1948.       } else if (curr_char == '"') {
  1949.         break;
  1950.       }
  1951.     };
  1952.  
  1953.       } else if (curr_char == '\'') {
  1954.  
  1955.     /* nuke character quotes -- must be on same line */
  1956.     may_flush = TRUE;
  1957.     while (!feof(fpin)) {
  1958.       prev_char = curr_char;
  1959.       if ((curr_char = getc(fpin)) == '\n') {
  1960.         syntax_err("unexpected newline in character constant");
  1961.         line_count++;
  1962.       } else if (curr_char == '\\') {
  1963.         prev_char = curr_char;
  1964.         curr_char = getc(fpin);
  1965.       } else if (curr_char == '\'') {
  1966.         break;
  1967.       } 
  1968.     }
  1969.  
  1970.       } else if (curr_char == '*' && prev_char == '/') {
  1971.  
  1972.     /* nuke comments */
  1973.     num_comment++;
  1974.     while ((curr_char = getc(fpin)) != EOF) {
  1975.  
  1976.       /* test for end of comment */
  1977.       if (curr_char == '\n') line_count++;
  1978.       if ((curr_char == '/') && (prev_char == '*')) {
  1979.         break;
  1980.       }
  1981.       prev_char = curr_char;
  1982.  
  1983.     }
  1984.     curr_char = ' ';
  1985.  
  1986.       } else if (curr_char == '/' && prev_char == '/') {
  1987.  
  1988.     /* nuke C++ comments (don't count it) */
  1989.     while ((curr_char = getc(fpin)) != EOF) {
  1990.  
  1991.       /* test for end of comment */
  1992.       if (curr_char == '\n') {
  1993.         line_count++;
  1994.         break;
  1995.       }
  1996.       prev_char = curr_char;
  1997.  
  1998.     }
  1999.     curr_char = ' ';
  2000.  
  2001.       } else if (curr_char == '{') {
  2002.  
  2003.     depth++;
  2004.     code_info[count++] = curr_char;
  2005.  
  2006.       } else if (curr_char == '}') {
  2007.  
  2008.     --depth;
  2009.     if (count > 0) code_info[count++] = curr_char;
  2010.     if (may_flush) {
  2011.       if (depth == 0) may_flush = FALSE;
  2012.       code_info[count = 0] = '\0';
  2013.     }
  2014.  
  2015.       } else {
  2016.     /* just copy on the off chance */
  2017.     code_info[count++] = curr_char;
  2018.       }
  2019.  
  2020.       /* now note what was last encountered */ 
  2021.       prev_char = curr_char;
  2022.  
  2023.     }
  2024.  
  2025.   }
  2026. }
  2027.  
  2028.